﻿using System;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Actya.Core;
using Actya.Core.Infrastructure;
using Actya.Core.Infrastructure.Logging;
using Actya.Core.SiteStructure;

namespace Actya.Web.Infrastructure
{
	public class CmsRequestHttpHandler : IHttpHandler
	{
		private readonly MvcHandler _mvcHandler;

		public CmsRequestHttpHandler(RequestContext requestContext) 
		{
			this._mvcHandler = new MvcHandler(requestContext);
		}

		public void ProcessRequest(HttpContext httpContext)
		{
			var serviceLocator = DependencyResolver.Current;
			var siteService = serviceLocator.GetService<ISiteService>();
			var pageService = serviceLocator.GetService<IPageService>();
			var logger = LogManager.GetLogger(this.GetType());
			var routeData = this._mvcHandler.RequestContext.RouteData;

			if (logger.IsDebugEnabled)
			{
				logger.Debug("Starting request for {0}", httpContext.Request.RawUrl);
			}

			// Setup CMS context
			var cmsContext = serviceLocator.GetService<ICmsContext>();

			// Try to get the site
			var site = siteService.FindSiteByHostUrl(cmsContext.Host.Settings.HostUrl);
			if (site == null)
			{
				throw new NullReferenceException(string.Format("There is no site found for host {0}.", cmsContext.Host.Settings.HostUrl));
			}
			cmsContext.Site = site;

			// If routedata contains a tempurl value, we're in preview mode.
			var tempUrl = routeData.Values["tempurl"] as string;
			var isPreview = tempUrl != null;

			// Try to get page
			var path = String.Empty;
			if (isPreview)
			{
				path = tempUrl;
			}
			else
			{
				path = "/" + routeData.Values["path"] as string;
				path = path != null ? VirtualPathUtility.AppendTrailingSlash(path) : "/";

				// Find homepage path from navigation.
				if (path == "/")
				{
					var homePageUrl = site.GetHomePageUrl();
					if (homePageUrl != null)
					{
						path = homePageUrl;
					}
				}
			}

			cmsContext.Page = pageService.FindPageByUrl(path);

			try
			{
				// Replace route values
				PageType pageType;
				var theme = site.DefaultTheme ?? "Default";
				if (cmsContext.Page != null && (cmsContext.Page.IsActive || isPreview))
				{
					// TODO: Security

					// Get page layout
					var pageLayout = site.GetPageLayoutById(cmsContext.Page.Layout);
					pageType = cmsContext.Site.GetPageTypeById(pageLayout.PageType);
					if (!String.IsNullOrEmpty(pageLayout.Theme))
					{
						theme = pageLayout.Theme;
					}
				}
				else
				{
					// Page not found. 
					pageType = cmsContext.Site.GetPageTypeById(PageTypeNames.NotFound);
				}
				routeData.Values["controller"] = pageType.Controller;
				routeData.Values["action"] = pageType.Action;
				routeData.Values["theme"] = theme;

				// Create controller
				var controller = ControllerBuilder.Current.GetControllerFactory()
					.CreateController(this._mvcHandler.RequestContext, pageType.Controller);

				controller.Execute(this._mvcHandler.RequestContext);
				if (logger.IsDebugEnabled)
				{
					logger.Debug("Finished request for {0}", httpContext.Request.RawUrl);
				} 
			}
			catch (Exception ex)
			{
				logger.Error(ex); 
				throw;
			}
			finally
			{
				// Remove page when in preview mode.
				if (isPreview && cmsContext.Page != null && cmsContext.Page.Url == tempUrl)
				{
					if (logger.IsDebugEnabled)
					{
						logger.Debug("Deleting preview page {0}, {1}", cmsContext.Page.Url, cmsContext.Page.Title);
					}
					pageService.DeletePage(cmsContext.Page);
				}
			}
		}

		public bool IsReusable
		{
			get { return false; }
		}
	}
}